<template>
  <q-dialog v-model="pop" persistent>
    <q-card :style="{width: width, 'max-width': '90vw'}">
      <q-card-section class="row items-center q-pb-none">
        <div class="text-h6">{{config.title || ''}}</div>
        <q-space />
        <q-btn icon="close" flat round dense v-close-popup />
      </q-card-section>

      <q-card-section>
        <searchArea :fieldlist="config.search" @search="search" @reset="search" v-if="!!config.search" />

        <q-table
          v-if="!!config.table"
          dense
          :title="config.table.title || ''"
          :rows="data"
          :columns="config.table.columns"
          :row-key="keyId"
          v-model:pagination="pagination"
          :loading="loading"
          :filter="filter"
          :rows-per-page-options="[5, 10, 25, 50]"
          @request="onRequest"
          binary-state-sort
          :selection="selection"
          v-model:selected="selected"
          :visibleColumns="visibleColumns"
          style="height: calc(50vh);"
          class="my-sticky-virtscroll-table"
        >
          <template v-slot:body="props">
            <q-tr :props="props">
              <q-td>
                <q-checkbox dense v-model="props.selected" />
              </q-td>
              <q-td :key="col.name" :props="props" v-for="col in props.cols" @click="rowClick(props.row)">
                <slot :name="'body-'+col.name" v-bind:props="props">
                  {{ col.value }}
                </slot>
              </q-td>
            </q-tr>
          </template>

          <template v-slot:bottom-row="props" v-if="config.table.columns.filter(v => v.footer).length > 0">
            <q-tr class="bg-yellow-2 text-center text-bold summary-line">
              <td></td>
              <q-td v-for="(col, idx) in props.cols" :key="idx" :class="col.footer && col.footer.class || 'text-bold'">
                {{ col.footer && col.footer.label ? typeof col.footer.label === 'function' ? col.footer.label(data) : col.footer.label : ''}}
              </q-td>
            </q-tr>
          </template>
        </q-table>
      </q-card-section>

      <q-card-actions align="right">
        <q-btn flat :label="buttonLabel[1] || '取消'" color="primary" v-close-popup @click="cancel" />
        <q-btn :label="buttonLabel[0] || '选择'" color="primary" @click="submit" />
      </q-card-actions>
    </q-card>
  </q-dialog>
</template>

<script>
import { defineComponent } from 'vue';
import { mapState } from 'pinia';
import { useStore } from 'stores/store';
import searchArea from 'src/components/SearchArea.vue';

export default defineComponent({
  components: {
    searchArea
  },
  props: {
    /** 配置说明：
     * config.title {string} 对话框标题
     * config.api {string} 数据接口url地址
     * config.search {object} 过滤条件配置，匹配 SearchArea
     * config.table {object} 数据结果表格，详细见下
     * config.table.label {string} 表格标题
     * config.table.multiple {boolean} 是否可多选 true - 多选 false - 单选
     * config.table.key {string} 关键字段名
     * config.table.columns {array} 字段配置
     */
    config: {
      type: Object,
      default: () => {}
    },
    size: { // 对话框宽度尺寸，sm: '350px',md: '50vw',lg: '80vw'
      type: String,
      default: 'md'
    },
    buttonLabel: { // 按钮的文字
      type: Array,
      default: () => ['选择', '取消']
    }
  },
  emits: ['submit'],
  data () {
    return {
      loading: false,
      pagination: {
        sortBy: '',
        descending: true,
        page: 1,
        rowsPerPage: 10,
        rowsNumber: 0
      },
      data: [],
      selected: [],
      pop: false,
      promiseResult: null
    }
  },
  mounted () {

  },
  methods: {
    onRequest (props) {
      if (!this.config.api) return;

      // eslint-disable-next-line prefer-const
      let { page, rowsPerPage, sortBy, descending } = props.pagination;
      let filter = props.filter;
      if (this.config.preFilter) {
        filter = { ...filter, ...this.config.preFilter };
      }

      this.loading = true;
      if (this.config.table.key && !sortBy) {
        sortBy = this.config.table.key;
      }

      const startRow = (page - 1) * rowsPerPage;
      const count = rowsPerPage;

      this.$axios.post(this.config.api, { startRow, count, filter, sortBy, descending })
        .then(({ data }) => {
          this.pagination.rowsNumber = data.rowsNumber;
          this.data = data.data;
          this.pagination.page = page;
          this.pagination.rowsPerPage = rowsPerPage;
          this.pagination.sortBy = sortBy;
          this.pagination.descending = descending;
          this.loading = false;
        });
    },
    search () {
      this.onRequest({
        pagination: this.pagination,
        filter: this.filter
      })
    },
    submit () {
      this.$emit('submit', this.selected);
      this.pop = false;
      this.promiseResult.resolve(this.selected);
    },
    show (data) {
      this.pop = true;
      if (data) {
        this.data = data;
        this.pagination.rowsNumber = data.length;
      }

      return new Promise((resolve, reject) => {
        this.promiseResult = { resolve, reject };
      });
    },
    hide () {
      this.pop = false;
    },
    cancel () {
      this.$emit('submit', null);
      this.pop = false;
      this.promiseResult.resolve(null);
    },
    rowClick (row) {
      const keyId = this.keyId;
      const idx = this.selected.findIndex(v => v[keyId] == row[keyId]);
      if (idx > -1) {
        this.selected.splice(idx, 1);
      } else {
        if (this.selection === 'multiple') {
          this.selected.push(row);
        } else {
          this.selected = [row];
        }
      }
    }
  },
  computed: {
    ...mapState(useStore, ['defaultImg']),
    filter: {
      get () {
        const filter = {};
        for (const field in this.config.search) {
          filter[field] = this.config.search[field].value
        }
        return filter;
      },
      set (val) {
        if (typeof val === 'object') {
          for (const field in val) {
            this.config.search[field].value = val[field];
          }
        }
      }
    },
    width () {
      const allSize = {
        sm: '350px',
        md: '50vw',
        lg: '80vw'
      };

      return allSize[this.size];
    },
    selection () {
      return this.config.table.multiple ? 'multiple' : 'single';
    },
    visibleColumns () {
      return this.config.table.columns.filter(v => v.visible !== false).map(v => v.name);
    },
    keyId () {
      return this.config.table.key || 'id';
    }
  },
  watch: {
    pop (val) {
      if (val) {
        this.selected = [];
        this.search();
      }
    }
  }
});
</script>

<style lang="scss">
.q-tree__node--selected {
  background-color: $grey-4;
}
.q-tree__avatar {
  border-radius: 10%;
}
.delete {
  text-decoration: line-through red;
}

.summary-line {
  position: sticky;
  z-index: 1;
  bottom: 0;
}
</style>
